home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 147
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan).7z
/
Gekkan Dennou Club - 2000.8 Vol. 147 (Japan) (Track 1).bin
/
tools
/
ask
/
gmd
/
source
/
gmd.s
< prev
next >
Wrap
Text File
|
2000-02-16
|
55KB
|
2,014 lines
*********************************************************************
* GMD:GetMojiDriver V2.0
* Copyright (C) 1996-98,2000 by AIG-Soft
*********************************************************************
.include defines.mac
.include fefunc.dis
.include pspdef.mac
.include gmd.mac
.lall * マクロを展開して表示する(主にデバッグ用)
.ifndef _FNTADR
_FNTADR equ $16 * IOCS _FNTADR
.endif
ZAREA equ 1024 * ZAREA>=HAREAかつ4の倍数のこと
HAREA equ 256 *
ZMASK equ ZAREA-1 * bit mask
HMASK equ HAREA-1 * bit mask
*********************************************************************
* 常駐ルーチン
*********************************************************************
.text
.even
DevHead: * デバイスヘッダー
.dc.l -1 * next device none
.dc.w %11000000_00100000 * char device/IOCTRL ok/RAW
* ?? ? 0000
.dc.l Dev_start
.dc.l Dev_main
DevName .dc.b '@MOJI ' * devive name
* 12345678 * /Gで@GMDになる
GMDsym .dc.b 'AIG-GMD ' * GMD Symbol
*********************************************************************
* ワーク1
*********************************************************************
* 固定値(この位置は変更しないこと;gmd.macで参照している)
API: .dc.l APImain * APIアドレス
Ver1: .dc.b 2 * バージョン番号整数桁
Ver2: .dc.b 0 * バージョン番号小数桁:x1-x9(v1.01とか)は表せない
.even
*--------------------------------------------------------------------
* 変化値
ProcAD: .dc.l 0 * このプロセスの先頭アドレス(!=DevHead/常駐解除時に必要)
Dev_A5: .dc.l 0 * a5 save work
*
Zcodes .dc.l 0 * ここはワークエリアそのものではなく
Hcodes .dc.l 0 * そのアドレスを格納する
* 以下の4つは必ず並べること(一気処理するから)
Zsumx .ds.b ZAREA * 各ハッシュ値になるキャラクター数
Hsumx .ds.b HAREA * Z~は全角,H~は半角
Ztops .ds.w ZAREA * codes内での各ハッシュ値毎の先頭位置
Htops .ds.w HAREA *
*
WriteAD .dc.l NonErr * API_Read/ReadTangoの書き込みルーチンアドレス
GroupAD .dc.l WDGroup * API_ReadTangoのGroupルーチンアドレス
badrs .dc.l -1 * 1回前の画面アドレス
by .dc.w -1 * 1回前のy座標
fdev .dc.b 0 * device driver flag : 0:常駐プログラム , <>0:デバイスドライバー
Fbmode .dc.b 0 * ワークの位置 : =0:プログラム後部 , <>0:高位メモリー
JLock .dc.b 0 * 常駐解除ロックカウント : =0:解除可能 , >0:解除不可
CurSw .dc.b 0 * カーソル状態(=0:非表示,<>0:表示)
RevMode .dc.b 0 * 反転文字まで読むかどうか(=0:読まない,<>0:読む)
.even
*********************************************************************
* APIルーチン
*********************************************************************
APImain:
* コマンドサーチ&実行
* d0.b=コマンド(未定義コマンドは暴走する)
* d0.l以外は保存
* あらかじめスーパーバイザーモードにしてから呼び出すこと
*(カーソルやフォントROMを直接いじるから)
* APImain内ではd0,d7,a0,a1以外破壊しない。
* d1-d6,a2-a6は引数として予約している。
movem.l d1-d7/a0-a6,-(sp)
moveq.l #0,d7 * for .b -> .l
move.b d0,d7 * command d0.b = d7.l
add.w d7,d7 * *2 (for word)
moveq.l #0,d0 * for .b/.w -> .l
move.w CtableN(pc,d7.w),d7
jsr CtableN(pc,d7.w) * 実行 -> d0.l
*
movem.l (sp)+,d1-d7/a0-a6
rts
*
* コマンドジャンプアドレス
CtableN: * 数値コマンド(0~番号順)
.dc.w API_reserve-CtableN * 未定義
.dc.w API_Read1-CtableN * <-d1.l ->d0.l
.dc.w API_ReadTango-CtableN * <-d1.l ->d0.l
.dc.w API_Read-CtableN * <-d1.l,d2.w ->d0.l
.dc.w API_SetWriter-CtableN * <-a2.l ->d0.l
.dc.w API_SetGroup-CtableN * <-a2.l ->d0.l
.dc.w API_MoveCursor-CtableN * <-d1.w
.dc.w API_ReadVer-CtableN * ->d0.w
.dc.w API_JLock-CtableN * ->d0.b
.dc.w API_JUnlock-CtableN * ->d0.b
.dc.w API_DevNameA-CtableN * <-a2.l
.dc.w API_RevMode-CtableN * <-d1.l
.even
*********************************************************************
* 基本内部ルーチン1:内部状態設定/参照
*********************************************************************
API_ReadVer: * バージョン読みだし
move.w Ver1(pc),d0 * d0.h.b=整数,d0.l.b=小数
API_reserve: * 未定義コマンド
rts
*--------------------------------------------------------------------
API_JLock: * 常駐ロック
* -> d0.b ロックカウント
* 特にチェックはしていないが、.bの+領域0~128段のみ可能
move.b JLock(pc),d0
addq.b #1,d0
move.b d0,JLock
rts
*
API_JUnlock: * 常駐アンロック
move.b JLock(pc),d0
subq.b #1,d0
bmi @f * マイナスにはしない
move.b d0,JLock
@@: rts
*--------------------------------------------------------------------
API_RevMode: * 反転文字読み取りモード
tst.l d1
bmi @f * -1:現在モード読み取り
sne RevMode * d1=0->0,<>0->$ffに限定
@@: moveq.l #0,d0 * for .b=.l
move.b RevMode(pc),d0
rts
*********************************************************************
* 基本内部ルーチン2:文字読みとりメイン
*********************************************************************
* 以下の基本ルーチンは必ずスーパーバイザーモードで動かすこと
*********************************************************************
* IOCS _FNTADRの代わり
* ちょっとでも早くなるようにIOCSを直接呼び出す
FNTADR:
moveq.l #8,d2 * フォントサイズ固定(8/16*16)
FNTJMP: jmp 0.l * d0,d1,d2破壊
AFNTADR equ FNTJMP+2 * IOCS _FNTADRのアドレス(直接飛ぶため)
*--------------------------------------------------------------------
LSum:
* 全角文字フォントハッシュ計算
* a1 <- font adrs (fb[2*16])
* a2は破壊しないこと
* -> d0.l.w : ハッシュ値(マスクはせず), NOCHR=空白文字である(s160不定)
* d0.h.w : 第2指標(s160)
move.l d7,-(sp)
*
lea 2(a1),a0 * p=&fb[2]
moveq.l #0,d2 * s16=0
moveq.l #0,d7 * s160=0
moveq.l #11-1,d0 * 11lines = 1~11
@@: moveq.l #0,d1 * for .b -> .w
move.b (a0),d1 * *p.b (左半分のみ)
add.w d1,d2 * s16+=*p
move.w (a0)+,d1 * eor.w (a0),d7が出来ないので
eor.w d1,d7 * 半角処理時に左右分けされるのでビット演算以外使えない
dbra d0,@b
*
tst.w d2 * s16=0?
bne 1f * No
* 空白の可能性有り
moveq.l #16/2-1,d0 * 16lines = 0~15
@@: tst.l (a1)+ * *p.w*2=0?(2ライン分一気チェック)
bne 1f * No = 空白ではない
dbra d0,@b
moveq.l #-1,d2 * 空白の印:move.w #NOCHR,d0だけど、高速化のため
*
1: move.w d7,d0 * s160.h.w / 半角の時はs160は上位8ビットのみ使うこと(&$ff00)
swap d0
move.w d2,d0 * s16.l.w
*
move.l (sp)+,d7
rts
*--------------------------------------------------------------------
FontCmp macro mask,tops,codes,sumx,cnt,HIKAKU,haba
* ハッシュ表からコードを読み取ってフォント比較
Local L1,L2,L3,L4
* d5.l.w <- s16
* d5.h.w <- s160
.if haba==1 * 半角の時
move.w #$ff00,d0 * s160の下位8ビットを無効にする(半角は幅8ドットなので)
swap d0
move.w #mask,d0
and.l d5,d0
move.l d0,d4 * d4.h.w=s160
.else
move.l d5,d4 * d4.h.w=s160
move.w d5,d0 * s16
and.w #mask,d0 * s16&mask
.endif
*
lea sumx(pc),a0
clr.w d4 * for .b -> .w (h.wは使用中なのでmoveq.lはだめ)
move.b (a0,d0.w),d4 * sumx[s16]
subq.w #1,d4 * -1 for dbra
*
add.w d0,d0 * tops[s16] ; topsは.wだから
move.l codes(pc),a2
lea tops(pc),a0
add.w (a0,d0.w),a2 * p=&codes[tops[s16]] (codesは32768より小さいので.wで届く)
*
L1: swap d4 * d4.h.w=ループカウント <-> .l.w=s160
cmp.w (a2)+,d4 * s160==*p++(s160)?
beq L4 * -> Yes
* s160が不一致:フォントは絶対一致しない
addq.w #2,a2 * cを飛ばす
bra L2 * 次の文字へ
*
L4: move.w (a2)+,d3 * c=*p++
move.w d3,d1 * c
bsr FNTADR * d0,d1,d2破壊
move.l d0,a1 * ->Font adrs(from ROM)
lea fb(pc),a0 * fb(from TEXT)
*
moveq.l #cnt-1,d1 * cnt lines (-1 for dbra)
L3: HIKAKU * フォント比較ルーチン
bne L2 * 不一致
dbra d1,L3
* 一致
moveq.l #haba,d0 * d0.l=$000幅_code : 幅
swap d0
move.w d3,d0
bra RCret * return(c) ; (マクロ外部のラベル)
*
L2: * 不一致
swap d4 * d4.l.w=ループカウンタ
dbra d4,L1
endm
Zhikaku macro
* 全角フォント比較
cmp.l (a1)+,(a0)+
endm
Hhikaku macro
* 半角フォント比較
cmp.b (a1)+,(a0)+
addq.w #1,a0 * 画面フォントは+2ずつ、ROMフォントは+1ずつ
* a?のaddはフラグが変わらない
endm
*---------------------------
ReadChar:
* 1文字読みとり
* d0.h.w=tx , d0.l.w=ty
* -> d0.l.w : 文字 (NOCHR=該当文字がない)
* d0.h.w : 文字幅-1 : 0=半角(1/2,1/4角文字を含む) , 1=全角
* d0以外破壊しない
movem.l d1-d7/a0-a2,-(sp)
*
* 読みとりテキストアドレス算出
* d0.h.w=tx , d0.l.w=ty
* x座標は連続する場合が多いので、前回の値を覚えて再計算を省き高速化する
cmp.w by,d0 * 前回とy座標が同じ?
bne @f
* 前回とy座標が同じ=x座標分だけ再計算(高速化のため)
move.l badrs,a1
swap d0 * d0.h.w=ty , d0.l.w=tx
add.w d0,a1 * x座標のみ更新
bra 10f
*
@@: * 新規アドレス計算
move.w d0,by * 今回のy座標を記録
move.l #TPLANE0,a1 * TPLANE0
add.l MTXOFST.w,a1 * +*TXOFST(ショートアドレッシング)
swap d0 * d0.h.w=ty , d0.l.w=tx
move.w d0,d6 * tx保存
clr.w d0 * = and.l #$ffff0000,d0 * ty(.h)のみ
lsr.l #5,d0 * ty>>5 = ty<<11 = ty*2048(16*TLSIZE:128)
add.l d0,a1
move.l a1,badrs * 今回のアドレスを記録(x=0のアドレス)
add.w d6,a1 * +tx
10: move.l a1,a2
add.l #TPSIZE,a2 * TPLANE1
*
moveq.l #0,d6 * 反転処理中でないの印
* 文字フォント読みとり(常に16dot=2byte*16line)
lea fb(pc),a0 * fb(読みとりバッファー)
moveq.l #0,d7 * bit0&左半分全0判定用
moveq.l #16-1,d1 * 16lines
* 高速化のため座標別に読みとりを変える
* 68030機種では偶数座標処理だけでいける
move.l a1,d0
btst.l #0,d0 * アドレス判定(奇数/偶数)
beq xeven * -> 偶数アドレス
* 奇数アドレス : byte単位
@@: move.b (a2)+,d0 * TPLANE1
or.b (a1)+,d0 * |TPLANE0
move.b d0,(a0)+
or.b d0,d7 * bit0判定用(左側)
move.b (a2),d0
or.b (a1),d0
move.b d0,(a0)+
lea 127(a1),a1 * next line
lea 127(a2),a2 * next line
dbra d1,@b
bra.s FontChk
*
* 偶数アドレス : word単位
xeven: move.w (a2),d0 * TPLANE1
or.w (a1),d0 * |TPLANE0
move.w d0,(a0)+
or.w d0,d7 * bit0判定用
lea 128(a1),a1 * next line
lea 128(a2),a2 * next line
dbra d1,xeven
move.w d7,-(sp)
move.b (sp)+,d7 * d0.l.h.b -> d0.l.l.b ; 左側
*
FontChk:
* フォント-文字判定
lea fb(pc),a1 * fb (TEXT)
bsr LSum * 全角用ハッシュ計算(s16/s160)
cmp.w #NOCHR,d0 * s16=NOCHR? : 全角分空白?
beq RCspc * Yes -> return(半角SPCにする)
* 空白ではない
move.l d0,d5 * s16(l.w)/s160(h.w)
*
* 全角・半角どちららしい?
tst.b d7
beq @f * 全ライン全ビット0=なら空白だが、左半分が空白の全角文字
* があるので、この時は常に全角文字優先にする。
btst.l #0,d7 * bit0=1:ne;全角 , 0:eq;半角
beq Hankaku
*
@@: moveq.l #1,d7 * 全角優先の印にする
Zenkaku: * 全角フォント比較
FontCmp ZMASK,Ztops,Zcodes,Zsumx,2*16/4,Zhikaku,2 * 一致ならRCretへ
* 全角では一致するフォントがない
btst.l #0,d7 * bit0=1:ne;全角 , 0:eq;半角
beq RCnret * 半角優先時に全角が終わったら終了
*
Hankaku: * 半角比較
* 半角スペースではないか?
tst.b d7 * 左側全ライン全ビットor値=0ならスペース
beq RCspc * スペースである
* スペースではない
FontCmp HMASK,Htops,Hcodes,Hsumx,16,Hhikaku,1 * 一致ならRCretへ
* 半角では一致するフォントがない
btst.l #0,d7 * bit0=1:ne;全角 , 0:eq;半角
beq Zenkaku * 半角優先時なら全角へ
*
RCnret: * 一致するフォント全く無し
tst.b RevMode * 反転文字も読み取る?
beq @f * いいえ
* 読み取る
tst.b d6 * もうすでに反転文字処理した?
bne @f * Yes
* 反転文字処理へ
st d6 * 反転処理中の印
* フォント反転
lea fb(pc),a1 * fb (TEXT)
moveq.l #16/2-1,d0 * 2ラインまとめて処理
1: not.l (a1)+ * 全ビット反転
dbra d0,1b
bra FontChk * 元に戻ってもう一度処理へ
*
@@: * 半角スペース相当で扱う時ため幅1にしておく
move.l #$0001_0000|NOCHR,d0 * $0001ffff (moveqにしないこと)
RCret: movem.l (sp)+,d1-d7/a0-a2
rts
RCspc: * 半角スペース
move.l #$0001_0020,d0
bra.s RCret
*--------------------------------------------------------------------
SetCur:
* d1.l <- x,y : (-1,-1)なら現在のカーソル座標
* -> d7.l -1:カーソル移動する , <>-1:戻すカーソル座標
move.l CSRX.w,d7 * 現在カーソル位置保存(カーソル移動しないの印)
* 画面を越える座標の時は現在カーソル位置とする
* (-1,-1)も越える
* 1024dot*1024line=128桁*64行まで対応
cmp.l #128.shl.16+64,d1
bcs CUROFF * No (0~,0~)
* 現在カーソル位置:カーソルは移動
move.l d7,d1
moveq.l #-1,d7 * カーソル移動するの印
CUROFF: * d1.l <- x,y
move.l d0,-(sp)
move.b CSRSWITCH.w,CurSw * 現在の状態を保存
IOCS _B_CUROFF * カーソルoff
move.l (sp)+,d0
rts
ResetCur:
* d1.l <- x,y
* d7.l <- -1:カーソル移動する , <>-1:戻すカーソル座標
tst.l d7 * カーソル移動する?
bpl CURON * No (0~,0~)
move.l d1,CSRX.w * カーソルを移動
CURON:
tst.b CurSw * 元がonならonする
beq @f
move.l d0,-(sp)
IOCS _B_CURON * カーソルon
move.l (sp)+,d0
@@: rts
*--------------------------------------------------------------------
API_Read1:
* 指定座標から1文字読みとり
* long GMDRead1(xy)
* <- d1.h.w=x , d1.l.w=y ((-1,-1)で現在のカーソル位置、カーソルは常に動かない)
* -> d0.l.w : 読みとった文字のコード (NOCHR=読み取れない)
* d0.h.w : 読みとった文字の幅
move.l CSRX.w,d0 * 現在のカーソル座標
cmp.l #128.shl.16+64,d1
bcc @f * >= -> (-1,-1):現在カーソル位置
move.l d1,d0 * 指定座標
@@: bsr CUROFF * カーソルoff
bsr ReadChar
bsr CURON * カーソルon
rts
*--------------------------------------------------------------------
API_SetWriter:
* ReadTango/Readの書き込みルーチン設定
* void GMDSetWriter(int (*func)())
* Read/ReadTangoの書き込みルーチンを設定する
* <- a2 : 書き込みルーチンアドレス
* 書き込みチェックなどはそのルーチン内で行う
* 引数は4(sp)で受ける , h.w=文字幅(1/2) , l.w=文字コード
* d0-d2/a0-a2以外保存すること , -> d0.l : 0=ok,<0=error
cmp.l #0,a2
bne @f
lea NonErr(pc),a2 * a2=0のときはデフォルトにする
@@: move.l WriteAD(pc),d0 * 元のアドレスを返す
move.l a2,WriteAD
rts
*--------------------------------------------------------------------
API_SetGroup:
* ReadTangoの文字コードグループ設定
* void GMDSetGroup(int (*func)())
* ReadTangoのGroupルーチンを設定する
* <- a2 : Groupルーチンアドレス
* 引数は4(sp)で受ける , h.w=文字幅(1/2) , l.w=文字コード
* d0-d2/a0-a2以外保存すること , -> d0.l : 0=ok,<0=error
cmp.l #0,a2 * a2=0のときは標準Groupに設定する
bne @f * それ以外はユーザー設定
lea WDGroup(pc),a2
@@: move.l GroupAD(pc),d0 * 元のアドレスを返す
move.l a2,GroupAD
rts
*--------------------------------------------------------------------
API_ReadTango:
* 指定座標からの単語単位読みとり
* long GMDReadTango(xy)
* d1.l <-> x,y : (-1,-1)なら現在カーソル位置からカーソル移動付き
* -> d0.l : 読みとった文字数 : バイトではなく半角/全角文字共に1と数える。
bsr SetCur * カーソル設定&off : x,y -> d1.l
move.l WriteAD(pc),a3 * 書き込みルーチンアドレス
move.l GroupAD(pc),a4 * Groupルーチンアドレス
moveq.l #-1,d4 * 読みとった文字数(後で+1するため)
moveq.l #-1,d6 * 最初のgroup
@@: bsr ReadTANGO1 * -> d0.w(group)
addq.l #1,d4 * 文字数+1
move.w d0,d6
bpl @b * group>=0
* d1.l <- x,y
tst.l d4 * 文字を読み取っている?
bne @f * 確実に
cmp.w #NOCHR,d3 * いきなり読み取れなかった?
bne @f * no
* まったく読み取れていない
* カーソルをx+1する
moveq.l #1,d3
bsr MoveCur * カーソル移動
@@: bsr ResetCur * カーソル設定&on
move.l d4,d0 * 読みとった文字数
rts
*--------------------------------------------------------------------
ReadTANGO1:
* 指定座標からの1文字読みとり(単語単位読みとり準備付き)
* d1.l <-> x,y
* d6.w <- 前のグループ(最初は<0)
* a3 <- 書き込みルーチン
* a4 <- Groupルーチン
* -> d3.w : 読み込んだ文字
* -> d0.w : >=0:今度のグループ , -1:中断 , -2:書き込みエラー
movem.l d4-d6,-(sp)
* d1.l=x,y
bsr ReadSub * -> d0.l.w=文字 , d0.h.w=文字幅 (d3も同じ)
beq 4f * Yes
* 読み取れている
move.l d3,-(sp) * 4+2(sp)で受けること
jsr (a4) * Groupルーチン : -> d0.w
addq.w #4,sp
cmp.w d0,d6 * 前のグループと同じ?
beq 3f * Yes
* 違うときはここまで(中断)
tst.w d6 * 前のグループ<0?
bmi 3f * Yes : 前との比較はしない
* 前のグループと違うときはここまで
move.l d4,d1 * 座標復帰
4: moveq.l #-1,d0 * 中断
bra.s @f
*
3: * 前と同じグループなので書き込む
move.w d0,d5 * グループ退避
bsr WriteSub * 書き込み&カーソル移動
bne @f * エラーが発生している
move.w d5,d0 * グループ復帰>0
@@: movem.l (sp)+,d4-d6
rts
*--------------------------------------------------------------------
ReadSub:
* 1文字読み込み
move.l d1,d4 * 座標保存
move.l d1,d0 * d0.l=x,y
bsr ReadChar * -> d0.l.w=文字 , d0.h.w=文字幅
move.l d0,d3 * 保存
cmp.w #NOCHR,d0 * 読み取れていない?
rts
WriteSub:
* 文字書き込み&カーソル移動
* d3.l <- h.w=文字幅(1/2) , l.w=文字
* d4.l <- カーソル座標
* a3 <- 書き込みルーチン
* -> d3.w = 文字
* -> d0.l : =0:ok , <>0:error
move.l d3,-(sp)
jsr (a3) * 書き込みルーチン
addq.w #4,sp
move.l d4,d1 * 座標復帰
tst.l d0 * 書き込めた?
bne @f * No
* カーソル移動(d0.l=0)
swap d3 * d3.w=文字幅
bsr MoveCur * -> d1.l=x,y (d3.h.w破壊)
swap d3 * d3.w=文字
tst.l d0 * z=1
rts
*
@@: * エラー
moveq.l #-2,d0 * WTERR(z=0)
rts
*--------------------------------------------------------------------
API_MoveCursor:
* 文字幅に合わせた現在カーソル移動
* d1.w <- 移動幅(1/2)
bsr CUROFF * カーソルoff
move.w d1,d3 * 移動幅
move.l CSRX.w,d1 * 現在カーソル
bsr MoveCur * 移動処理
move.l d1,CSRX.w * カーソル移動
bsr CURON * カーソルon
rts
*
MoveCur:
* カーソル移動
* d1.l <- x|y -> d1.l
* d3.w <- 移動幅(1/2)
* (d1),d3破壊
*(現在カーソルを移動させる時はカーソルをoffしてから行う必要がある)
swap d1 * y|x
add.w d3,d1 * x+=幅
cmp.w CSRXMAX.w,d1 * x>WX? (WXまではok)
bhi 2f * Yes
* x<=WX
swap d1 * x|y
bra.s 1f
*
2: * x>WX -> x=0~
subq.w #1,d3 * d3-1が新しい座標になる : d3=1->x=0 ...
move.w d3,d1
swap d1 * x|y
addq.w #1,d1 * y++
cmp.w CSRYMAX.w,d1 * y>WY?
bls 1f * no(y<=WY)
clr.w d1 * y=0
1:
rts
*--------------------------------------------------------------------
* 単語として読みとる区切り文字
HanGP: .dc.b ' ,;:()。、・',$22,$27,0 * 1byte
ZenGP: .dc.b '。、,',0,0 * 2byte(.wで読まれるので、EOTも0,0必要)
* よく出てくる順に置くこと
.even
WDGroup:
* 単語単位グルーピング(標準)
* 4(sp) <- h.w=文字幅(1/2) , l.w=code
* -> d0.w : グループ番号 (h.wは不定でいい)
moveq.l #1,d0 * 通常はグループ1
move.w 4+2(sp),d2 * 文字コード
cmp.w #$ff,d2 * code>=$ff?
bcc 1f * Yes -> 2バイト文字
moveq.l #0,d1 * for .b -> .w
* 1byte文字チェック
lea HanGP(pc),a0
@@: move.b (a0)+,d1
beq @f * end of table
cmp.w d1,d2 * 一致?
bne @b * no
* 一致したものはグループ2
moveq.l #2,d0
@@: rts
1: * 2byte文字チェック
lea ZenGP(pc),a0
@@: move.w (a0)+,d1
beq @f * end of table
cmp.w d1,d2 * 一致?
bne @b * no
* 一致したものはグループ2
moveq.l #2,d0
@@: rts
*--------------------------------------------------------------------
API_Read:
* 指定座標からの指定文字数分読みとり
* long GMDRead(xy,size)
* d1.l <-> x,y : (-1,-1)なら現在カーソル位置からカーソル移動付き
* d2.w <- size >0: 指定文字数(読み取れない文字があったら中止)
* <0:-指定文字数(読み取れない文字があっても半角スペースとして継続)
* =0:単語読み取り
* 画面上文字数は最大で128*64=8192なのでword単位で十分
* -> d0.l : 読みとった文字数 : バイトではなく半角/全角文字共に1と数える。
* 書き込みルーチンアドレス設定
moveq.l #0,d5 * 読み取れない文字=中止の印
tst.w d2 * size
beq API_ReadTango * size=0 : 単語読み取り
bpl @f * >0:指定文字数読み取り(読み取れない->中断)
* <0
sub.w d2,d5 * d5=d5-d2 = d5=0-d2 -> -d2>0
move.w d5,d2
moveq.l #1,d5 * 読み取れない文字=スペースで継続の印
@@: bsr SetCur * カーソル設定&off : x,y -> d1.l
move.l WriteAD(pc),a3 * 書き込みルーチンアドレス
moveq.l #-1,d4 * 読みとった文字数(後で+1するため)
subq.w #1,d2 * -1 or dbra
@@: bsr ReadSize1 * -> d0.w(文字)
addq.l #1,d4 * 文字数+1
cmp.w #WTERR,d0
bhi @f * 中断
dbeq d2,@b * 書き込みエラーでない
beq @f * エラーの時
addq.l #1,d4 * 最後まで読めた時は文字数+1
* d1.l <- x,y
@@: bsr ResetCur * カーソル設定&on
move.l d4,d0 * 読みとった文字数
rts
*--------------------------------------------------------------------
ReadSize1:
* 指定座標からの1文字読みとり(連続読み込み準備付き)
* d1.l <-> x,y
* d5.w <- =0:読み取れなかったら中断 , <>0:読み取れない文字は半角スペース
* a3 <- 書き込みルーチン
* d0.w -> 読み込んだ文字>0 , NOCHR:読み取れない , WTERR:書き込みエラー
movem.l d2-d4,-(sp)
* d1.l=x,y
bsr ReadSub * -> d0.l.w=文字 , d0.h.w=文字幅
bne 1f * no
* 読み取れていない
tst.w d5 * 中断?
beq @f * Yes
move.l #$0001_0020,d3 * 半角スペース(幅=1)
1: * 書き込む
bsr WriteSub * 書き込み&カーソル移動
bne @f * エラーが発生している
move.l d3,d0 * d0.w=文字
@@: movem.l (sp)+,d2-d4
rts
*********************************************************************
* 基本内部ルーチン5:デバイス名取得
*********************************************************************
API_DevNameA:
* a2 <- デバイス名格納エリア
lea DevName(pc),a0
moveq.l #8-1,d1 * -1 dbra
@@: move.b (a0)+,d0
cmp.b #' ',d0 * ' 'の直前まで
beq 2f
move.b d0,(a2)+
dbra d1,@b * または8バイトまで
2: clr.b (a2) * EOS
rts
*********************************************************************
* デバイスドライバー:コマンド解析&初期処理
* デバイスドライバーは(たぶん)常にスーパーバイザーモードで走る。
*********************************************************************
Dev_start:
move.l a5,Dev_A5 * save リクエストヘッダーアドレス
rts
*********************************************************************
Dev_main:
movem.l d1-d7/a0-a6,-(sp) * push register
move.l Dev_A5(pc),a5 * a5 <- リクエストヘッダーアドレス
*
moveq.l #0,d0 * for .b -> .l
move.b 2(a5),d0 * d0.l <- コマンド番号
add.w d0,d0 * *2
move.w comtable(pc,d0.w),d0 * read call offset address
jsr comtable(pc,d0.w) * call subroutines
*
move.l d0,d1
move.b d1,3(a5) * set error code (low)
lsr.w #8,d1 * high -> low (8bit)
move.b d1,4(a5) * set error code (high)
movem.l (sp)+,d1-d7/a0-a6 * pop register
rts
*********************************************************************
.even
comtable: * コマンドアドレス(相対アドレス表)
.dc.w Dev_init-comtable * 初期化
.dc.w COM_ERR-comtable
.dc.w COM_ERR-comtable
.dc.w NonErr-comtable * ioctrl in
.dc.w NonErr-comtable * 入力
.dc.w NonErr-comtable * 先行入力
.dc.w NonErr-comtable * 入力バッファーチェック
.dc.w NonErr-comtable * バッファークリア
.dc.w Dev_Write-comtable * 出力(verify off)
.dc.w Dev_Write-comtable * 出力(verify on)
.dc.w NonErr-comtable * 出力ステータスチェック
.dc.w COM_ERR-comtable
.dc.w NonErr-comtable * ioctrl out
.even
*********************************************************************
* エラーコマンド
COM_ERR:
move.w #$5003,d0 * $50 = 中止&無視 , $03 = コマンドコードが不正
rts
*********************************************************************
Dev_Write: * 出力(verify on/off)
* "x,y,size,fname" / "x.y.size.fname"
* ファイルがオープンできないときは単に動作しないだけ
* エラーは読みとりサイズ=-1を返す
move.l 14(a5),a2 * buffer
move.l 18(a5),d3 * size
bsr DevWriteSub
move.l d0,18(a5) * <0:エラー , >=0:読みとった文字数
* ただし、デバイスとしてのエラーは出さない
NonErr: moveq.l #0,d0 * no error
rts
*--------------------------------------------------------------------
Atoi:
* 10進文字列読み取り(負号,',','.'対応)
* a2 <-> str
* -> d0.w : 数値($0000-$ffff) , $ffffffff=エラー
move.l d1,-(sp)
moveq.l #1,d1 * 負号無し
cmp.b #'-',(a2)
bne @f
* '-'がある
moveq.l #0,d1 * 負号あり
addq.w #1,a2
subq.l #1,d3
beq Aerr1 * 負号しかない
@@: swap d1 * for .b -> .w (.h.w=0/1)
moveq.l #0,d0 * num=0
@@: move.b (a2)+,d1
beq Aret * EOS
cmp.b #'0',d1
bmi Aerr * '0'より小さい -> 数字文字でない
cmp.b #'9',d1
bhi Aerr1 * Yes -> 数字文字でない
* '0'~'9'
sub.b #'0',d1
add.w d0,d0 * *2
add.w d0,d1
add.w d0,d0 * *4
add.w d0,d0 * *8
add.w d1,d0 * *8+(*2+c) = *10+c
subq.l #1,d3
bne @b * 文字列終わりまで
Aret: swap d1
tst.w d1 * 負号あり?
bne @f * No
sub.w d0,d1 * 0-d0
move.w d1,d0 * d0.w
@@: move.l (sp)+,d1
rts
Aerr: * 途中でbase進文字でない文字が出て来た
cmp.b #',',d1 * ,
beq Aret * Yes
cmp.b #'.',d1 * .
beq Aret * Yes
* ここでは数字の後にファイル名があるため、数字のみで終わることはない。
* 従って、そういう時はエラーにする。
* cmp.b #' ',d1 * コントロールコード($1a,$0d,$0a等)は文字列終了とみなす
* bmi Aret
Aerr1: * エラー
moveq.l #-1,d0
move.l (sp)+,d1
rts
*--------------------------------------------------------------------
DevWriteSub:
* a2.l <- 文字列(EOSでは終わっていない)
* d1.l <- 文字列長
* 座標読みだし -> d1.l
bsr Atoi * x -> d0.w
tst.l d0
bmi 1f * 数字エラー
move.w d0,d1
swap d1
bsr Atoi * y -> d0.w
tst.l d0
bmi 1f * 数字エラー
move.w d0,d1 * d1=x|y
* サイズ読みだし -> d2.w
bsr Atoi
tst.l d0
bmi 1f * 数字エラー
move.w d0,d2
* ファイル名読みだし->fopen
pea 32.w * 通常ファイルとして作成
move.l a2,-(sp) * fname
* (a2)~はファイルなのでEOSがない
@@: cmp.b #' '+1,(a2)+ * そこで$1aまたは$0d/$0aをEOSにする
bpl @b
clr.b -1(a2) * EOS
DOS _CREATE
addq.w #8,sp
move.w d0,fp * fp
bmi DWSERR * error
* 読みとり
move.l WriteAD(pc),-(sp) * 書き込みルーチンを保存
move.l #FileWT,WriteAD * ここで使う書き込みルーチンを設定
* d1.l <- x,y / d2.w <- size
bsr API_Read * -> d0.l : 読みとった文字数
move.l (sp)+,WriteAD * 書き込みルーチンを戻す
* ファイルクローズ
move.l d0,-(sp) * d0保存
move.w fp,-(sp)
DOS _CLOSE
addq.w #2,sp
move.l (sp)+,d0 * d0復帰
1:
rts
DWSERR:
moveq.l #-1,d0
rts
FileWT:
* ファイル書き込みルーチン
* ReadSize1から呼び出される
move.l 4(sp),d0 * 文字コード
move.w d0,d1 * push d0
cmp.w #255,d1
bls 1f * 1バイト文字
* 2バイト文字である
* 分割して出力
move.w d0,-(sp)
move.b (sp)+,d0 * d0.l.h.b -> d0.l.l.b
bsr 1f * 上位バイト出力
move.b d1,d0 * 下位バイト出力
1: move.w fp,-(sp)
move.w d0,-(sp)
DOS _FPUTC
addq.w #4,sp
moveq.l #0,d0 * ok
rts
*********************************************************************
* ワーク2
*********************************************************************
* ここに置くワークは、常駐後に使われるもの
* これらのワークエリアは常駐後に利用可能になるので、
* 以下の非常駐ルーチンからは参照しないこと
* 常駐後に非常駐部分をワークエリアにする定義
* 必ずevenになるようにすること
fpsz equ 2 * .dc.w 0
fbsz equ 2*16 * .ds.b 2*16
fp: * ファイルポインタ
fb equ fp+fpsz * フォントバッファー
fb_end equ fb+fbsz
*********************************************************************
* ワークエリア転送ルーチン
*********************************************************************
* ワークエリアを低位メモリーに取るとき、mallocではなく常駐メモリーを多く取って
* プログラムの後ろに付ける。これは、メモリーの分断を防ぐためである。
* が、KSDと違ってGMDは初期化時にワークエリアを使うため、そのまま
* プログラムの後ろ(KEEP_ENDから)に取ることはできない。
* 従って、次の手順を取る。
* (1)/Hに関わらずMALLOC2で高位メモリーにワークを取る
* 初期化中は、このワークエリア内で処理する。
* /Hの時はこれで終わる。/Hでないときは、この転送ルーチンへ入る。
* (2)スタックポインターを初期状態に戻す
* (3)KEEP_ENDからにワークエリア内容をすべて転送する。
* (4)Zcodes/Hcodesのアドレスを変更する
* (5)先のワークエリアを解放する
* このルーチンそのものは常駐後にfbになる。
*
TrnsWork:
* /hがないとき+常駐終了時のみここにくる
* a0,a2<- 元のZcodes
* a1 <- KEEP_END
* d0.l <- ワークエリアサイズ(.w*2単位分)
* d1.l <- 常駐サイズ
* d7.l <- exit code
* 転送
@@: move.l (a0)+,(a1)+ * 元Zcodes~[.w*2]->KEEP_END
dbra d0,@b
* 高位メモリーワーク解放
pea (a2) * Zcodes
DOS _MFREE
addq.w #4,sp * めんどうなのでエラー処理は省略
*
tst.b fdev * DEVICE=?
beq ComEnd * No
* デバイスドライバー
moveq.l #0,d0 * エラー無し
rts
*
ComEnd: * コマンドライン
move.w d7,-(sp) * exit(?)
move.l d1,-(sp) * 常駐サイズ
DOS _KEEPPR
TrnsWorkEnd:
*--------------------------------------------------------------------
* 転送ルーチンがfbのサイズより小さいときはfbの最後がKEEP_END、
* 逆の時は転送ルーチンの最後がKEEP_END
*.if TrnsWorkEnd .gt. fb_end
*KEEP_END equ TrnsWorkEnd
*.else
KEEP_END equ fb_end
*.endif
* 常駐固定部分最後+1
*********************************************************************
* 非常駐ルーチン
*********************************************************************
* 初期化ルーチン(デバイスドライバー)
*********************************************************************
* 外部参照
.xref _DevCheck
.xref _DevCheck2
.xref SetDevLink
.xref ResetDevLink
*--------------------------------------------------------------------
* 初期化ルーチンは、コマンドラインから起動の時はユーザーモードで、
* デバイスドライバーの時はスーパーバイザーモードで走る(はず)。
* 本当は、デバイスドライバー常駐のものを操作する時のため、
* ここでスーパーバイザーモードにしてからInitSubを呼び出したい。
* しかしそうすると、setblockがエラーを出してしまう。
* したがって、複雑になるが、InitSub中で必要時のみスーパーバイザーにする。
*--------------------------------------------------------------------
main: * コマンドライン常駐
* clr.b fdev * コマンドライン組み込み
move.l sp,oldstack * 元のスタック保存
lea initsp(pc),sp * 初期化中用のスタックに設定
* PROGRAM=の時スタックオーバーを起こすのでスタックを変更しておく
bsr InitSub * 初期化
move.l d0,d7 * exit code保存
tst.l d1 * 常駐サイズあり?
bne @f * Yes
* 常駐以外終了
move.l oldstack(pc),sp * スタックを戻す
1: move.w d7,-(sp) * exit(?)
DOS _EXIT2
*
@@: * デバイスリンクに入り込む
lea DevHead(pc),a0
bsr SetDevLink
*
* 常駐終了
move.l oldstack(pc),sp * スタックを戻す
* スタックを戻すのでこれ以降、深いスタックを使わないこと
tst.b Fbmode * 高位メモリー?
bne ComEnd * Yes
WrkChg: * 低位メモリーの時
* ワークエリアアドレス変更
* TrnsWorkを小さくするために、できるだけこちらに置いている
move.l Zcodes(pc),a2 * 元のZcodes保存
lea KEEP_END(pc),a1
move.l a1,Zcodes * ZcodesをKEEP_ENDに変更
move.w Zall(pc),d0
add.w d0,d0 * Zcodes[]は.w;全角文字数は<8000なので大丈夫
add.w d0,a1 * s160も入れるので*2
add.w d0,a1
move.l a1,Hcodes * Hcodes=&Zcodes[Zall*2*2]
*
lea KEEP_END(pc),a1 * (a0) -> (a1)
move.l a2,a0 * a0=元のZcodes(復帰)
move.l ZHall(pc),d0 * 転送サイズ(.l=.w*2単位)
subq.l #1,d0 * -1 for dbra
bra TrnsWork
*--------------------------------------------------------------------
Dev_init: * デバイスドライバ:初期化
st.b fdev * DEVICE=組み込み
bsr ChangeLine * コマンドライン変換
pea CrLf(pc)
DOS _PRINT * 1行改行してからメッセージを出す
addq.w #4,sp
*
lea cline0(pc),a2
bsr InitSub * 初期化
tst.l d1
beq @f * 常駐以外終了
* 常駐終了
add.l #DevHead,d1 * d1<-常駐部最終アドレス
move.l d1,14(a5)
*
tst.b Fbmode * 高位メモリー?
beq WrkChg * No -> 転送へ
@@:
rts
* init時のd0.l<>0は白帯にならずに組み込めないメッセージとなる
*
*--------------------------------------------------------------------
PrintDevName:
* デバイス名表示
* 改行付き
bsr PrintDevName0
pea CrLf(pc)
DOS _PRINT
addq.w #4,sp
rts
PrintDevName0:
* デバイス名表示
* エラー表示のため改行しない
* a0/d1は破壊してはいけない
movem.l a0/d1,-(sp)
*
pea DeviceMes(pc)
DOS _PRINT
addq.w #4,sp
*
lea.l DevName-DevHead(a0),a0
moveq.l #0,d0 * for .b = .w
moveq.l #8-1,d1 * デバイス名は8文字まで
@@: move.b (a0)+,d0
move.w d0,-(sp)
DOS _PUTCHAR
cmp.w #' ',(sp)+ * スペースを1つ表示したら終了
dbeq d1,@b
*
movem.l (sp)+,d1/a0
rts
*********************************************************************
* フォントハッシュ用意
*********************************************************************
CheckZMoji:
* そのコードの全角文字が存在するかどうかを調べる
* Zhaniでもある程度存在しない文字は省いてある(それを踏まえてのルーチン)
* d4.w=code -> z=1:存在する , z=0:存在しない
* c1=1バイト目(d4.h.b) , c2=2バイト目(d4.l.b)
* c1<$81,$85~$87,>=$edは存在しない
* c1=$ec で c2>=$9fは存在しない
* c1=$88,$eb で c2=$40~$9eは存在しない
* 2バイト目チェック
* $40~$fcがある ただし $7fはない
cmp.b #$40,d4 * c2<$40?
bcs @f * Yes -> 存在しない
cmp.b #$fc,d4 * c2>$fc?
bhi @f * Yes -> 存在しない
cmp.b #$7f,d4 * c2==$7f?
beq @f * Yes -> 存在しない
okkanji: * <- 外部から参照される
moveq.l #0,d0 * コードが存在するの印(Z=1)
rts
*
@@:
moveq.l #1,d0 * コードがおかしいの印(Z=0)
rts
*--------------------------------------------------------------------
.even
Zhani: * 全角文字範囲
* 1バイト目が存在しないページは与えないこと
* start,end
.dc.w $889f,$9872 * 第1水準
.dc.w $824f,$8396 * 英数字かな
.dc.w $8141,$824e * 記号(全角スペースを除く)
.dc.w $8397,$84fc * 非漢字
.dc.w $9873,$9ffc * 第2水準(1)
.dc.w $e040,$eafc * 第2水準(2)
.dc.w $eb9f,$ec9e * 全角外字
.dc.w 0 * end of table
Hhani: * 半角文字範囲(空白は除く)
* 半角は存在チェックをしないので、存在する文字のみ与えること
* start,end
.dc.w $0021,$007e * 1バイト半角
.dc.w $00a1,$00df * 1バイト半角カタカナ
.dc.w $80a6,$80dd * 1/2角平仮名
.dc.w $f021,$f07e * 上付き
.dc.w $f0a1,$f0df
.dc.w $f1a6,$f1dd * 上付き平仮名
.dc.w $f221,$f27e * 下付き
.dc.w $f2a1,$f2df
.dc.w $f3a6,$f3dd * 下付き平仮名
.dc.w $f420,$f4ff * 半角外字(表示可能なものだけ)
.dc.w $f520,$f5ff
.dc.w 0 * end of table
* 文字数
* InitReadCharだけでなくInitSubでも読み出す
Zall .dc.w 0 * 全角文字数
Hall .dc.w 0 * 半角文字数
ZHall .dc.l 0 * 全角+半角文字数(.wで十分だが後の処理のため.lにする)
WKsize .dc.l 0 * ZHall*sizeof(word)*2 : 可変ワークエリアサイズ
RWTable * Read/Write Table
* size,bufferの2データがセット
.dc.l 2,Zall * 2=sizeof(?all)
.dc.l 2,Hall
.dc.l (ZAREA+HAREA)*(1+2),Zsumx * Zsumx,Hsumx,Ztops,Htopsを一気読み書き
RWTBLSZ .equ 3 * このテーブルのデータ数
HSIZE equ 8 * ヘッダーサイズ : 2*longword(変えないこと)
*
Header: * ファイルヘッダー(サイズ=HSIZE)
.dc.b 'GMD'
Hver: .dc.b 0 * メジャーバージョン=Ver1+'0'が入る
.dc.b $0d,$0a,$1a,$00
*
HBuff .ds.b HSIZE * ヘッダー読み込み用バッファー
.even
*--------------------------------------------------------------------
LSumH:
* 半角文字フォントハッシュ計算
* a1 <- font adrs (fb)
* a2は破壊しないこと
* -> d0.l.w : ハッシュ値(s16) , NOCHR=空白文字である(s160不定)
* d0.h.w : 第2指標(s160)
move.l d7,-(sp)
*
lea 1(a1),a0 * p=&fb->buffer[1]
moveq.l #0,d7 * s160=0
moveq.l #0,d2 * s16=0
moveq.l #11-1,d0 * 1~11line
@@: moveq.l #0,d1 * for .b -> .w
move.b (a0),d1 * s16+=*p++
add.w d1,d2
move.b (a0)+,d1 * eor.b (a0),d1が出来ないので
eor.b d1,d7 * s160^=*p
dbra d0,@b
*
tst.w d2 * s16=0?
bne @f * no = 空白ではない
tst.b (a1) * line 0
bne @f * <>0
* line 1~11までは0なので再計算しない
moveq.l #-1,d0 * 空白の印:move.w #NOCHR,d0
tst.l 12(a1) * line 12,13,14,15
beq 1f * ==0 : 空白である
@@: move.w d7,d0 * s160
lsl.w #8,d0 * s160の値を上位8ビットへ移動する&下位8ビット=0
swap d0 * .h.w
move.w d2,d0 * s16.l.w
*
1: move.l (sp)+,d7
rts
*--------------------------------------------------------------------
CalcSumSubZ:
* 全角文字チェック
* d5.w <- mode
movem.l d3-d7/a3-a6,-(sp)
move.w #ZMASK,d3 * mask
lea Zhani(pc),a1 * 文字コード範囲群
move.l Zcodes(pc),a2
lea Ztops(pc),a3
lea Zsumx(pc),a4
lea LSum(pc),a5 * d0-d2/a0-a1破壊
lea CheckZMoji(pc),a6 * d0破壊
bra.s @f
CalcSumSubH:
* 半角文字チェック
* d5.w <- mode
movem.l d3-d7/a3-a6,-(sp)
move.w #HMASK,d3 * mask
lea Hhani(pc),a1 * 文字コード範囲群
move.l Hcodes(pc),a2
lea Htops(pc),a3
lea Hsumx(pc),a4
lea LSumH(pc),a5 * d0-d2/a0-a1破壊
lea okkanji(pc),a6 * ダミー関数 : 常時checkmoji(c)=0 : "その文字はある"を返す
@@: *
swap d3 * d3.h.w=mask
moveq.l #0,d6 * all=0
3: move.w (a1)+,d4 * d4.w=st
beq 5f * -> end
move.w (a1)+,d3 * d3.w=ed
*
move.l a1,d7 * a1保存
1: * 文字判定
jsr (a6) * check_moji(d4) : d0破壊
bne 2f * この文字は存在しない
*
move.w d4,d1 * c
bsr FNTADR * d0,d1,d2破壊
move.l d0,a1 * ->Font adrs(from ROM)
jsr (a5) * bsr LSum : d0-d2/a0-a1破壊
cmp.w #NOCHR,d0 * 空白フォント?
beq 2f * Yes
* d0.w=s16
swap d3
and.w d3,d0 * s16&HMASK
swap d3
lea (a4,d0.w),a0 * sumx[s16]
tst.w d5 * mode=0?
beq @f * Yes
*
moveq.l #0,d1 * for .b -> .w
move.b (a0),d1 * d1.w=sumx[s16]
add.w d1,d1
add.w d1,d1 * codesはword*2だから
add.w d0,d0 * topsはwordだから
add.w (a3,d0.w),d1 * d1.w=tops[s16]+sumx[s16]*(.w*2)
swap d0 * d0.h.w=s160
move.w d0,(a2,d1.w) * codes[d1.w+0]=s160(先に比較するので先に格納する)
move.w d4,2(a2,d1.w) * codes[d1.w+2]=c
*
@@: addq.b #1,(a0) * sumx[s16]++
addq.w #1,d6 * all++
2: addq.w #1,d4 * c++
cmp.w d3,d4 * <=ed?
bls 1b * Yes
*
move.l d7,a1 * a1復帰
bra 3b
*
5: move.l d6,d0 * d0.w <- all
tst.w d5 * mode?
movem.l (sp)+,d3-d7/a3-a6
rts
*----------------------------------
CalcSum:
* d5.w <- mode (0/1)
* Zsumx+Hsumxをクリア
lea Zsumx(pc),a0
move.w #(ZAREA+HAREA)/4-1,d0 * .l単位で消すから(moveqではあふれるので駄目)
@@: clr.l (a0)+
dbra d0,@b
*
clr.l a1
IOCS _B_SUPER * super visor mode
move.l d0,-(sp)
*
* 全角文字計算
bsr CalcSumSubZ * -> d0(all)
bne @f
move.w d0,Zall
@@: * 半角文字計算
bsr CalcSumSubH * -> d0(all)
bne @f
move.w d0,Hall
@@: *
move.l (sp)+,d0
bmi @f * 元からsuper visorであった
move.l d0,a1
IOCS _B_SUPER * user mode
@@:
rts
*----------------------------------
ReadWriteSub:
* d4.w <- fp
* d2.w <- mode (0=Read,1=Write)
* -> d0.b (0=ok,-1=error)
lea RWTable(pc),a0
moveq.l #RWTBLSZ-1,d1 * 読み込みデータ数-1 for db??
@@: move.l (a0)+,a1
move.l a1,-(sp) * size
move.l (a0)+,-(sp) * buffer
move.w d4,-(sp) * fp
tst.w d2 * WriteMode?
bne 2f * Yes
* ReadMode
DOS _READ
bra.s 3f
*
2: * WriteMode
DOS _WRITE
3: lea 4*2+2(sp),sp
cmp.l d0,a1 * =size?
dbne d1,@b * 読み書きサイズが実際のそれと異なる時はエラー
*
sne d0 * <>sizeの時<>0.b
rts
*----------------------------------
Fclose:
* 単なるファイルクローズ
* d4.w <- fp
move.w d4,-(sp) * fp
DOS _CLOSE
addq.w #2,sp
rts
*----------------------------------
SetHashWork:
* -> d1.l : <0=error , >0=ok:Zcodes
* mi pl (0はない)
* 全角+半角で一気に処理する
moveq.l #0,d0 * for .w -> .l
move.w Zall(pc),d0 * Zall
add.w Hall(pc),d0 * +Hall -> ZHall
move.l d0,ZHall * 記録
* メモリー確保(d0)
add.l d0,d0 * ZHall*sizeof(word)
add.l d0,d0 * *2=ワークエリアサイズ
move.l d0,WKsize * 記録
move.l d0,-(sp) * size
move.w #2,-(sp) * ここでは常に高位メモリーに確保
DOS _MALLOC2
addq.w #6,sp
move.l d0,d1 * d1=adrs
bmi @f * メモリーが確保できない(d1<0)
*
move.l d1,Zcodes * Zcodes=m
moveq.l #0,d0 * for .w -> .l
move.w Zall(pc),d0
add.l d0,d0 * Zcodesはword*2だから
add.l d0,d0
add.l d1,d0 * m+Zall(word*2)
move.l d0,Hcodes * Hcodes=&Zcodes[Zall*2];
* d1>0=Zcodes
@@:
rts
*----------------------------------
ReadHashFile macro
* ハッシュファイル読みとり
local L1,L2,L3,L4,L5
* a4 <- fname
* ファイルオープン
clr.w -(sp) * read mode
pea (a4) * fname
DOS _OPEN
addq.w #6,sp
move.l d0,d4 * fp
bmi IRC2 * <0=そのファイルはない->テーブル作成
* ヘッダー読み込み
pea HSIZE.w * size
pea HBuff(pc) * buf
move.w d4,-(sp) * fp
DOS _READ
lea 10(sp),sp
cmp.l #HSIZE,d0 * ==size?
bne L2 * 読み込めない
* ヘッダーチェック
* 8バイトなので2*longwordでチェックする
lea Header(pc),a0
lea HBuff(pc),a1
cmp.l (a0)+,(a1)+
bne L5
cmp.l (a0)+,(a1)+
beq L4
L5: * ヘッダーが異常
bsr Fclose
moveq.l #-3,d0 * return($fffd)
rts
*
L4: * ファイル読みとり
moveq.l #0,d2 * mode=2:read
bsr ReadWriteSub * -> d0.b(ret)
move.b d0,d3 * ret=
bne L1 * ret
* ハッシュワークを確保する
bsr SetHashWork * -> d1.l(Zcodes)
bpl L3 * OK
* メモリーが確保できない
bsr Fclose
moveq.l #0,d0 * return(0)
rts
*
L3: move.l WKsize(pc),d0 * ZHall*sizeof(word)
move.l d0,d2 * size保存
move.l d0,-(sp) * size
move.l d1,-(sp) * Zcodes
move.w d4,-(sp) * fp
DOS _READ
lea 10(sp),sp
cmp.l d0,d2 * ==size?
L2: sne d3 * ret : d3.b <- $00/$ff
L1: bsr Fclose
tst.b d3 * ret?
beq IRC1 * No
moveq.l #-2,d0 * return($fffe)
rts
endm
*----------------------------------
WriteHashFile macro
* ハッシュファイル書きだし
local L1,L2,L3
* a4 <- fname
* ファイル作成
pea 32.w * 通常ファイルとして作成
move.l a4,-(sp) * fname
DOS _CREATE
addq.w #8,sp
move.l d0,d4 * fp
bmi L1 * <0=error
* ヘッダー書き出し
pea HSIZE.w * size
pea Header(pc) * buf
move.w d4,-(sp) * fp
DOS _WRITE
lea 10(sp),sp
cmp.l #HSIZE,d0 * ==size?
bne L3 * 書き込めない
*
* ファイル書きだし
moveq.l #1,d2 * mode=1:write
bsr ReadWriteSub
move.b d0,d3 * ret=
bne L2
*
move.l WKsize(pc),d0 * ZHall*sizeof(word)
move.l d0,d2 * size保存
move.l d0,-(sp) * size
move.l Zcodes(pc),-(sp) * buf
move.w d4,-(sp) * fp
DOS _WRITE
lea 10(sp),sp
cmp.l d0,d2 * ==size?
L3: sne d3 * d3.b <- $00/$ff
L2: bsr Fclose
tst.b d3 * ret?
beq IRC1 * No
* ファイル作成時エラー
* 作りかけのファイルを削除する
* CREATしているから問題ない
move.l a4,-(sp)
DOS _DELETE
addq.w #4,sp
L1: moveq.l #-1,d0 * return($ffff)
rts
endm
*----------------------------------
* codes内でのハッシュ毎の先頭位置を決める→tops[]
CalcTops:
* a0 <- sumx
* a1 <- tops
* d0.w <- AREAサイズ-1 (-1 for dbra)
moveq.l #0,d2 * p=0
@@: move.w d2,(a1)+ * tops[i].w=p
moveq.l #0,d1 * for .b -> .w
move.b (a0)+,d1 * sumxは.b
add.w d1,d1
add.w d1,d1 * *4(codes[]は.w*2)
add.w d1,d2
dbra d0,@b
rts
*----------------------------------
InitReadChar:
* int InitReadChar(fname)
move.b Ver1(pc),d0 * メジャーバージョンを入れる
add.b #'0',d0 * +'0'するため、上限は$4e('0'~$7eまで)となるが
move.b d0,Hver * そこまでバージョンが上がることはなかろう
*
move.l 4(sp),a4 * fname
tst.b (a4)
beq IRC2
* ファイルの指定があるとき
ReadHashFile * ハッシュファイル読み込み
*
IRC2: * メッセージ表示
pea TableMakeMes(pc)
DOS _PRINT
addq.w #4,sp
*
* (1)sumの計算(その分布調査)
moveq.l #0,d5 * mode
bsr CalcSum
*
* (2)全文字分のコード表ワークエリア確保
bsr SetHashWork * -> d1.l
bpl @f * OK
* メモリー確保出来ないエラー
moveq.l #0,d0 * return(0)
rts
*
@@: * (3)コード表ワークのsum毎の先頭位置を決める
lea Zsumx(pc),a0
lea Ztops(pc),a1
move.w #ZAREA-1,d0 * -1 for dbra
bsr CalcTops
*
lea Hsumx(pc),a0
lea Htops(pc),a1
move.w #HAREA-1,d0 * -1 for dbra
bsr CalcTops
*
* (4)もう一度sumを計算し、今度はコード表に格納する
moveq.l #1,d5 * mode
bsr CalcSum
*
* メッセージ消去
pea TableClrMes(pc)
DOS _PRINT
addq.w #4,sp
*
* (5)ファイル指定がある時は、そのファイルを作成する
move.l 4(sp),a4 * fname
tst.b (a4)
beq IRC1 * ファイル名指定がない
* ファイルの指定があるとき
WriteHashFile * ハッシュファイル書きだし
*
IRC1: move.l ZHall(pc),d0 * return(ZHall)
rts
*********************************************************************
ChangeLine:
* DEVICE=形式のパラメーターをコマンドライン型に変換する
* 読み取りルーチン共用化のため
move.l 18(a5),a0 * 元のコマンドライン
* 最初の00まではプログラム名なので飛ばす
@@: tst.b (a0)+
bne @b
*
lea cline(pc),a2 * 変換後ライン
moveq.l #0,d1 * length
CL1: tst.b (a0)
beq CLend * 0,0で終了
@@: addq.l #1,d1 * len++
move.b (a0)+,(a2)+
bne @b
* 0をスペースに直す
move.b #' ',-1(a2)
bra.s CL1
*
CLend: clr.b (a2) * EOS
move.b d1,cline0
rts
*--------------------------------------------------------------------
* コマンドライン解析(a2=コマンドライン)
* この中ではa0は壊さないこと(プロセス管理ポインタを参照するため)
ChkARG:
clr.b HashName * ファイル名指定がないときのため(EOS)
tst.b (a2)+ * コマンドラインサイズ = 0?
bne arglp * No
* コマンドラインがない(プログラム名のみ)
* GMDではエラーにならない
move.w #$ff00,d0 * 注意(.b=0,.w!=0)
rts
*
arglp:
@@: * 空白飛ばし
move.b (a2)+,d0
cmp.b #' ',d0
beq @b
cmp.b #$09,d0 * TAB
beq @b
subq.w #1,a2 * a2が1つ進んでいるので戻す
*
tst.b d0 * end?
beq eos * Yes
* オプションは -? or /?
cmp.b #'-',d0
beq chkopt
cmp.b #'/',d0
beq chkopt
getarg: * オプション以外の引数はフォントハッシュファイル名とみなす
* HashNameにそれを転送
lea.l HashName(pc),a3 * bssなので(pc)にしない...本当は
@@: move.b (a2)+,d0
cmp.b #' ',d0 * SPCがあったら終わり
beq @f
cmp.b #$09,d0 * TABがあったら終わり
beq @f
move.b d0,(a3)+
bne @b
eos: * EOSを入れたら終了(この後にオプションはない)
moveq.l #0,d0 * ok(.b=0,.w=0)
rts
*
@@: clr.b (a3) * EOS
bra arglp * オプションチェックに戻る
chkopt: * オプションチェック
addq.w #1,a2 * skip '-' or '/'
move.b (a2)+,d0
beq argerr * -/のみでオプションがない
and.b #%11011111,d0 * 大文字化
*
lea ComFlags-2(pc),a6 * 後で+2するため-2しておく
tst.b fdev * DEVICE=?
beq @f * no
* DEVICE=時
lea DevFlags-2(pc),a6 * 後で+2するため-2しておく
@@: addq.w #2,a6
tst.b 1(a6) * Option名
beq argerr * 全てのオプションと比較終了 -> 規定外オプション
cmp.b 1(a6),d0 * オプションチェック
bne @b * 不一致
tst.b (a6) * すでにフラグがセットされている?
bne arglp * Yes : 飛ばす(2重指定なのでargerrにしてもよい)
st.b (a6) * セット
bra arglp * コマンドライン処理へ戻る
argerr:
moveq.l #-1,d0 * エラー(.b<>0)
rts
*--------------------------------------------------------------------
InitSub: * 初期化 -> d0.l:status , d1.l=常駐サイズ
* a5は壊さないこと
move.l a0,d7 * a0保存
lea HashName(pc),a0
* バージョン番号文字列作成
* a0.l = バッファー
moveq.l #0,d0
move.b Ver1(pc),d0 * 整数桁
FPACK __LTOS * d0.l(符号つき) -> 10進文字列化
move.b #'.',(a0)+ * 小数点
moveq.l #0,d0
move.b Ver2(pc),d0 * 小数桁
FPACK __LTOS * d0.l(符号つき) -> 10進文字列化
*
pea title1(pc) * タイトル前半表示
DOS _PRINT
pea HashName(pc) * バージョン番号
DOS _PRINT
pea title2(pc) * タイトル後半表示
DOS _PRINT
lea 4*3(sp),sp
move.l d7,a0 * a0復帰
*
bsr ChkARG * コマンドライン引数チェック
tst.b d0 * .wではない
bne usage * 引数がおかしい
*
* このあたりではa2は破壊しないこと
*
move.l a2,-(sp) * 重要
clr.l -(sp) * デバイス名格納せず
pea GMDsym(pc) * 隠しデバイス名
bsr _DevCheck2 * デバイスチェック
addq.l #8,sp
move.b d0,d7 * d7.b : 0=常駐してない(a0=不変=自己メモリーブロック)
* $ff=常駐している(a0=デバイスヘッダーアドレス=DevHead)
move.l (sp)+,a2 * 重要
*
tst.b rflag * -r : 常駐解除?
beq keep * no
*
* 常駐解除(device=では絶対に来ない)
*
tst.b d7 * 常駐している?
beq Err_NoKp * No -> error
* DEVICE=で常駐している時は解除不可
lea.l fdev-DevHead(a0),a1
IOCS _B_BPEEK * スーパーバイザーの中を覗くことがあるため
tst.b d0
bne Err_Dev * DEVICE=で組み込まれている
*
* ここに来るのはコマンドライン常駐の時のみ=ksdは必ずユーザーモード領域にいる
* 常駐ロックチェック
tst.b JLock-DevHead(a0) * =0?
bne Err_Lock * No:常駐ロック中
* すでに常駐しているものを解除
* ここに来るのはコマンドライン常駐の時のみ
move.l ProcAD-DevHead(a0),-(sp) * このプロセスの先頭アドレス
DOS _MFREE * 自己プロセスメモリー解放
addq.w #4,sp
tst.l d0
bmi Err_Kai * なぜかメモリー解放出来ない時
*
tst.b Fbmode * 高位モード?
beq @f * No
* 高位モードの時のみ:ワークエリアの解放
move.l Zcodes-DevHead(a0),-(sp) * Zcodes解放
DOS _MFREE
addq.w #4,sp
tst.l d0
bmi Err_WkNk * なぜかメモリー解放出来ない時
@@: * エラーが出た場合、プロセスがなくワークのみが残ることになる。
* 非常によろしくない。一言で言えば手抜きである。
*
* デバイスリンク解除
bsr ResetDevLink * a0=DevHead
*
* 常駐解除正常終了
pea.l MesRelease(pc) * 解除メッセージ
DOS _PRINT
addq.w #4,sp
*
moveq.l #0,d1 * 常駐しない
moveq.l #0,d0 * 正常終了:exit(0)
rts
*
* 常駐
*
keep: tst.b d7 * すでに常駐している?
bne Err_2Kp * Yes -> 2重常駐エラー
*
* デバイス名を変更する時はここで行う
tst.b gflag * デバイス名を@GMDにする?
beq @f * No
* @MOJI -> @GMD
move.b #'G',DevName+1
move.w #('M'<<8)|'D',DevName+2 * ここはワードで書き込める
move.b #' ',DevName+4
@@: * 同名デバイスもない?
movem.l a0-a2,-(sp) * 重要
pea DevName(pc)
bsr _DevCheck
addq.l #4,sp
movem.l (sp)+,a0-a2 * 重要
tst.b d0
bne Err_DevUse * 同名デバイスがある
* 同名デバイスもない
*
* 常駐していない->常駐処理
tst.b hflag * 高位メモリー?
sne.b Fbmode * Yes -> Fbmode=$ff
tst.b fdev
bne @f * -> DEVICE=常駐
* プログラム起動時にはフリーエリアの全てが起動プログラムに割り当てられているため、
* これを必要部分以外解放する。そうしないとMALLOC2が効かない。
* DEVICE=のときは不要(MALLOC2出来る)。
* a0=プログラムメモリ管理ポインタ
* a1=プログラム終了アドレス+1(.data,.bssを含む)
lea MPSIZ(a0),a0 * メモリー管理ポインタ分を飛ばす
move.l a0,ProcAD * このプロセスの先頭アドレス(!=DevHead)保存
sub.l a0,a1 * 当プログラムサイズ
move.l a1,-(sp) * 確保する領域サイズ
move.l a0,-(sp) * 確保する領域の先頭アドレス
DOS _SETBLOCK * 領域変更
addq.w #4*2,sp
tst.l d0
bmi Err_StBk * 領域が変更できない時=エラー
@@:
* IOCS _FNTADRのアドレス取得(高速化のため)
move.w #_FNTADR+$100,-(sp)
DOS _INTVCG
addq.w #2,sp
move.l d0,AFNTADR
* フォントハッシュ作成
movem.l d1-d5/a0-a4,-(sp)
pea HashName(pc) * フォントハッシュファイル名
bsr InitReadChar
addq.w #4,sp
movem.l (sp)+,d1-d5/a0-a4
cmp.w #$fffd,d0 * 必ず.wで比較
beq Ferror3 * Header Illegal
cmp.w #$fffe,d0 * 必ず.wで比較
beq Ferror1 * Can't Read
bhi Ferror2 * Can't Write (d0.w=$ffff)
tst.w d0
beq Err_Wrk * memory不足
*
move.l #KEEP_END-DevHead,d1 * 常駐サイズ:本体
tst.b Fbmode * 高位メモリー?
bne @f * Yes
* 低位メモリーの時はその分を加える
add.l WKsize(pc),d1 * +size
* このプロセスの占めるメモリー領域を拡大してワークも入るようにする
* 本当は、d1<initsp-DevHead=常駐サイズが元のプログラムサイズより小さくなる
* なら次のプロセスメモリーの拡大の前にスタックを元に戻す必要がある。
* 拡大したつもりが縮小になり、スタックが領域外に出てしまうためである。
* しかし、GMDでは通常は絶対にあり得ないので簡略化してここで行っている
move.l d1,d0
add.l #PSPSIZ-MPSIZ,d0 * プロセス管理ポインタ分も含める
move.l d0,-(sp) * new size
move.l ProcAD(pc),-(sp)
DOS _SETBLOCK
addq.w #8,sp
bmi Err_Wrk * メモリー不足
*
@@: pea MesRevMode(pc) * 反転文字読み取りモード表示
DOS _PRINT
lea MesRevOn(pc),a1
tst.b oflag * 反転文字ON?
sne.b RevMode * Yes -> RevMode=$ff
bne @f
lea MesRevOff(pc),a1
@@: pea (a1)
DOS _PRINT
addq.w #4*2,sp
*
pea MesKeep(pc) * 常駐メッセージ
DOS _PRINT
addq.w #4,sp
lea DevHead(pc),a0 * このプログラム内を参照
bsr PrintDevName * デバイス名表示
moveq.l #0,d0 * exit(0)
rts
*--------------------------------------
* エラー処理
*--------------------------------------
Ferror3: * ハッシュファイルでない
lea ErrIllHash(pc),a0
bra.s @f
Ferror2: * ファイルに書けない
lea ErrCantWtHash(pc),a0
bra.s @f
Ferror1: * ファイルが読めない
lea ErrCantRdHash(pc),a0
@@: bsr PrintErr
lea HashName(pc),a0 * ファイル名表示
bra.s error
*
Err_DevUse: * デバイス名がすでに使われている
lea DevHead(pc),a0 * このプログラム内を参照
bsr PrintDevName0
lea.l ErrDevUse(pc),a0
bra.s error
Err_StBk: * SetBlock出来ない
* lea.l ErrCantKpBuff2(pc),a0
* bra.s error
Err_Wrk: * ワークエリアが確保出来ない
lea.l ErrCantKpBuff(pc),a0
bra.s error
Err_NoKp: * 常駐していないのに解除しようとした
lea.l ErrNoKumikomi(pc),a0
bra.s error
Err_2Kp: * 2重常駐
lea DevHead(pc),a0 * このプログラム内を参照
bsr PrintDevName * デバイス名表示
lea.l ErrAlreadySet(pc),a0
bra.s error
*
Err_WkNk: * ワークエリアが解放できない
lea.l ErrCantResBuff(pc),a0
bra.s error
Err_Dev: * DEVICE=で組み込まれている
lea.l ErrCantDevice(pc),a0
bra.s @f
Err_Lock: * 常駐ロックされている
lea.l ErrCantJLock(pc),a0
@@: bsr PrintErr
Err_Kai: * 常駐解除不可
lea.l ErrCantRelease(pc),a0
bra.s error
*
usage: * 使用法
lea.l MesUsage(pc),a0
error: bsr PrintErr
lea CrLf(pc),a0
bsr PrintErr
*
moveq.l #0,d1 * 常駐しない
moveq.l #2,d0 * exit(2)
rts
*
PrintErr
* (a0)エラー出力へメッセージ表示
move.w #2,-(sp) * STDERR
pea.l (a0)
DOS _FPUTS
addq.w #2+4,sp
rts
*********************************************************************
* メッセージなど
*********************************************************************
.even
TableMakeMes: .dc.b 'フォントハッシュ作成中...',0
TableClrMes: .dc.b $0d,' ',$0d,0
title1: .dc.b 'GetMojiDriver V',0
title2: .dc.b ' Copyright 1996-98,2000 by AIG-Soft',$0d,$0a
* .dc.b ' Debug中 v001',$0d,$0a
.dc.b 0
MesKeep: .dc.b '組み込みました',$0d,$0a,0
MesRelease: .dc.b '解除しました',$0d,$0a,0
ErrNoKumikomi: .dc.b '組み込まれていません' * CrLfにつながる
CrLf .dc.b $0d,$0a,0
DeviceMes .dc.b 'デバイス名:',0
*
ErrCantRdHash .dc.b 'フォントハッシュファイルが読み込めません:',0
ErrCantWtHash .dc.b 'フォントハッシュファイルが書き込めません:',0
ErrIllHash: .dc.b 'フォントハッシュファイルではありません:',0
*ErrCantKpBuff2 .dc.b 'SetBlock不可で'
ErrCantKpBuff: .dc.b 'フォントハッシュワークが確保できません',0
ErrAlreadySet: .dc.b 'すでに組み込まれています',0
ErrDevUse .dc.b 'はすでに使用されています',0
*
ErrCantDevice: .dc.b 'DEVICE=で組み込まれています.',0
ErrCantJLock .dc.b '常駐ロックされています.',0
ErrCantResBuff: .dc.b 'フォントハッシュワークが解放できません.' * 次につながる
ErrCantRelease: .dc.b 'GMDは解除できません',0
MesUsage: .dc.b 'GMD [/h /g /o /r] [フォントハッシュファイル]',0
*
MesRevMode: .dc.b '反転文字読み取り:',0
MesRevOff: .dc.b '不' * 次につながる
MesRevOn: .dc.b '可能',$0d,$0a,0
*
*********************************************************************
* オプション
*********************************************************************
* オプション名はコマンド名と同じにする
.even
* .dc.b work,フラグキャラクター
* 1オプション分 1+1=2バイト
ComFlags: * コマンドライン時有効フラグ
rflag .dc.b 0,'R' * 常駐解除フラグ
DevFlags: * デバイスドライバ時にも有効フラグ
hflag .dc.b 0,'H' * 高位メモリー確保フラグ
gflag .dc.b 0,'G' * デバイス名を@GMDにする
oflag .dc.b 0,'O' * 反転文字を読むかどうか
.dc.b 0,0 * end of table
*********************************************************************
* 非常駐ルーチンが使うワーク
*********************************************************************
.bss
.even
oldstack .dc.l 0 * 元のスタックポイント
cline0 .dc.b 0 * 変換後コマンドラインサイズ
cline .ds.b 256 * コマンドライン変換
HashName .ds.b 96 * フォントハッシュファイル名
.stack
.even
.ds.l 256 * スタック(コマンドライン起動時のみ使用)
initsp:
*********************************************************************
.end main